package user_interface;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Arrays;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import controller.SimpleController;
import data.Solution;
import data.Task;

import model.SimpleModel;

public class UserInterface extends JFrame implements FBUserInterface {
	private final static long serialVersionUID = 1L;
	// Swing components
	private JPanel instrumentPanel, viewPanel;
	private JMenu fileMenu;
	private JMenuBar menuBar;
	private JTextArea consoleTextArea;
	private JPanel mapPanel;
	private JLabel currentFileLabel;
	private JTextField neighborhoodSizeTextField, maxIterationTextField, tabooListLengthTextField, randomSwappingNumberTextField, swappingProportionTextField;
	private JLabel neighborhoodSizeLabel, maxIterationLabel, tabooListLengthLabel, randomSwappingNumberLabel, swappingProportionLabel;
	private JButton calculateButton, pauseButton;
	// Main data
	private SimpleModel model;
	private SimpleController controller;
	private boolean pause_state = false;
	/**
	 * Constructor.
	 */
	public UserInterface(SimpleController controller, SimpleModel model) {
		super("Genethic alghoritm");
		// initialize window
		setLayout(new GridLayout(1, 1));
		//setResizable(false);
		setSize(1000, 800);
		setLocation(200,200);
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				UserInterface.this.controller.shutdown();
			}
		});
		
		// initialize data
		this.model = model;
		this.controller = controller;
		
		// initialize swing components
		create_menu_bar();
		create_instrument_panel();
		create_view_panel();
		
		// build
		setJMenuBar(menuBar);
		
		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, instrumentPanel, viewPanel);
		split.setResizeWeight(0.1);
		add(split);
		
		setVisible(true);
	}
	
	@Override
	public void setSolution(final Solution solution) {
		if(!SwingUtilities.isEventDispatchThread()) {
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
					setSolution(solution);
				}
			});
		} else {
			mapPanel.removeAll();
			
			Task task = model.getCurrentTask(); 
			class ActorData implements Comparable<ActorData>{
				int number;
				float salary;
				int day;
				float cost;
				public int compareTo(ActorData o) {
					if(cost > o.cost)
						return -1;
					if(cost < o.cost)
						return 1;
					return 0;
				};
			}
			ActorData[] actorData = new ActorData[task.getActorsNumber()];
			
			final float [] actorsSalary = task.getActorsSalary();
			final int actorsNumber = task.getActorsNumber();
			final int scenesNumber = task.getScenesNumber();
			final boolean [][] actorsScenesRelation = task.getActorsScenesRelation();
			for(int actorIndex = 0 ; actorIndex < actorsNumber ; ++actorIndex) {
				int firstSceneDay = scenesNumber;
				int lastSceneDay = 0;
				for(int sceneIndex = 0 ; sceneIndex < scenesNumber ; ++sceneIndex) {
					if(actorsScenesRelation[actorIndex][sceneIndex]) {
						final int sceneDay = solution.getScenesOrder()[sceneIndex];
						firstSceneDay = Math.min(firstSceneDay, sceneDay);
						lastSceneDay = Math.max(lastSceneDay, sceneDay);
					}
				}
				actorData[actorIndex] = new ActorData();
				actorData[actorIndex].number = actorIndex;
				actorData[actorIndex].salary = actorsSalary[actorIndex];
				if(lastSceneDay >= firstSceneDay) {
					actorData[actorIndex].cost = (lastSceneDay - firstSceneDay + 1) * actorsSalary[actorIndex];
					actorData[actorIndex].day = (lastSceneDay - firstSceneDay + 1);
				} else {
					actorData[actorIndex].cost = 0;
					actorData[actorIndex].day = 0;
				}
			}
			
			Arrays.sort(actorData);
			
			JButton costButton = new JButton("Cost = " + solution.getCost());
			costButton.setLocation(5, 5);
			costButton.setSize(200, 25);
			mapPanel.add(costButton);
			
			float maxCost = actorData[0].cost;
			float maxY = 25;
			float x_begin = 50;
			float y_begin = 50;
			for(int i = 0; i < actorData.length; i++) {
				JButton butt = new JButton("[" + Integer.toString(actorData[i].number) + "] " + Integer.toString(actorData[i].day) + "d * " + Float.toString(actorData[i].salary) + "$ = " + Float.toString(actorData[i].cost));
				float x = x_begin;
				float y = y_begin + i * maxY + 10;
				butt.setLocation((int)(x + 0.5), (int)(y + 0.5));
				butt.setSize(200, (int)maxY);
				JButton progress = new JButton();
				progress.setLocation((int)(x + 200 + 0.5), (int)(y + 0.5));
				float progress_x = (actorData[i].cost / maxCost) * 500;
				progress.setSize((int)(progress_x + 0.5), (int)maxY);
				Color c = new Color((actorData[i].cost / maxCost), (1 - (actorData[i].cost / maxCost)), 0);
				butt.setBackground(c);
				progress.setBackground(c);
				mapPanel.add(butt);
				mapPanel.add(progress);
			}
			mapPanel.setPreferredSize(new Dimension(700, (int)(actorData.length * maxY + 100)));
			mapPanel.updateUI();
			mapPanel.repaint();
		}
	}
	
	@Override
	public void print2console(String text) {
		consoleTextArea.append(text + "\n");
		consoleTextArea.setCaretPosition(consoleTextArea.getDocument().getLength());
	};
//=============================================================================
//------------------PRIVATE METHODS--------------------------------------------
	private void create_menu_bar() {
		menuBar = new JMenuBar();
		fileMenu = new JMenu("File");
		
		JMenuItem openFileMenu = new JMenuItem("Open");
		openFileMenu.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				JFileChooser fileChooser = new JFileChooser(".");
				Component parent = UserInterface.this;
				if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
					String fileName = fileChooser.getSelectedFile().getPath();
					currentFileLabel.setText("Please, waiting");
					try {
						model.openFile(fileName);
						currentFileLabel.setText("File : "
								+ fileChooser.getSelectedFile().getName());
					} catch (Exception ex) {
						consoleTextArea.append("Can't open file "
								+ fileChooser.getSelectedFile().getName() + "\n");
					}
				}
			}
		});
		fileMenu.add(openFileMenu);

		menuBar.add(fileMenu);
	}
	
	private void create_instrument_panel() {
		instrumentPanel = new JPanel(new GridLayout(1, 1));
		JPanel tmpPanel = new JPanel(new GridBagLayout());
		JScrollPane tmpScroll = new JScrollPane(tmpPanel);
		instrumentPanel.add(tmpScroll);

		// create components
		// File
		currentFileLabel = new JLabel("File : please open file");
		GridBagConstraints gbc = new GridBagConstraints(0,0,  2,1,  1,0,  GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(1, 1, 20, 1),  0,0);
		tmpPanel.add(currentFileLabel, gbc);

		// rp parameters
		neighborhoodSizeTextField = new JTextField("3");
		neighborhoodSizeLabel = new JLabel("neighborhood size :");
		gbc = new GridBagConstraints(0,1,  1,1,  0,0,  GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(1, 1, 1, 1),  0,0);
		tmpPanel.add(neighborhoodSizeLabel, gbc);
		gbc = new GridBagConstraints(1,1,  1,1,  1,0,  GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(1, 1, 1, 1),  30,0);
		tmpPanel.add(neighborhoodSizeTextField, gbc);
		
		maxIterationLabel = new JLabel("Max iteration :");
		maxIterationTextField = new JTextField("10000");
		gbc = new GridBagConstraints(0,2,  1,1,  0,0,  GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(1, 1, 1, 1),  0,0);
		tmpPanel.add(maxIterationLabel, gbc);
		gbc = new GridBagConstraints(1,2,  1,1,  1,0,  GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(1, 1, 1, 1),  30,0);
		tmpPanel.add(maxIterationTextField, gbc);

		tabooListLengthLabel = new JLabel("Taboo list length :");
		tabooListLengthTextField = new JTextField("0");
		gbc = new GridBagConstraints(0,3,  1,1,  0,0,  GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(1, 1, 1, 1),  0,0);
		tmpPanel.add(tabooListLengthLabel, gbc);
		gbc = new GridBagConstraints(1,3,  1,1,  1,0,  GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(1, 1, 1, 1),  30,0);
		tmpPanel.add(tabooListLengthTextField, gbc);
		
		randomSwappingNumberLabel = new JLabel("randomSwappingNumber :");
		randomSwappingNumberTextField = new JTextField("1");
		gbc = new GridBagConstraints(0,4,  1,1,  0,0,  GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(1, 1, 1, 1),  0,0);
		tmpPanel.add(randomSwappingNumberLabel, gbc);
		gbc = new GridBagConstraints(1,4,  1,1,  1,0,  GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(1, 1, 1, 1),  30,0);
		tmpPanel.add(randomSwappingNumberTextField, gbc);

		swappingProportionLabel = new JLabel("swappingProportion :");
		swappingProportionTextField = new JTextField("0.2");
		gbc = new GridBagConstraints(0,5,  1,1,  0,0,  GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(1, 1, 1, 1),  0,0);
		tmpPanel.add(swappingProportionLabel, gbc);
		gbc = new GridBagConstraints(1,5,  1,1,  1,0,  GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(1, 1, 1, 1),  30,0);
		tmpPanel.add(swappingProportionTextField, gbc);

		calculateButton = new JButton("Calculate");
		pauseButton = new JButton("Pause");
		gbc = new GridBagConstraints(0,6,  1,1,  1,1,  GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets(1, 1, 1, 1),  0,0);
		tmpPanel.add(calculateButton, gbc);
		gbc = new GridBagConstraints(1,6,  1,1,  0,1,  GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets(1, 1, 1, 1),  0,0);
		tmpPanel.add(pauseButton, gbc);
		pauseButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				pause_state = !pause_state;
				UserInterface.this.controller.pause(pause_state);
				if(pause_state)
					pauseButton.setText("Play");
				else
					pauseButton.setText("Pause");
			}
		});
		calculateButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// Get neighborhoodSize parameter
				Integer neighborhoodSize = 3;
				try {
					String neighborhoodSizeText = neighborhoodSizeTextField.getText();
					neighborhoodSize = new Integer(neighborhoodSizeText);
				} catch (Exception ex) {}				
				neighborhoodSizeTextField.setText(neighborhoodSize.toString());

				// Get max iteration
				Integer maxIteration = 10000;
				try {
					String maxIterationText = maxIterationTextField.getText();
					maxIteration = new Integer(maxIterationText);
				} catch (Exception ex) {
					maxIterationTextField.setText(maxIteration.toString());							
				}
				
				// Get taboo list length
				Integer tabooListLength = 0;
				try {
					String tabooListLengthText = tabooListLengthTextField.getText();
					tabooListLength = new Integer(tabooListLengthText);
				} catch (Exception ex) {
					maxIterationTextField.setText(tabooListLength.toString());							
				}
				
				// Get randomSwappingNumber
				Integer randomSwappingNumber = 1;
				try {
					String randomSwappingNumberText = randomSwappingNumberTextField.getText();
					randomSwappingNumber = new Integer(randomSwappingNumberText);
				} catch (Exception ex) {
					randomSwappingNumberTextField.setText(tabooListLength.toString());							
				}

				// Get randomSwappingNumber
				Float swappingProportion = 0.2f;
				try {
					String swappingProportionText = swappingProportionTextField.getText();
					swappingProportion = new Float(swappingProportionText);
				} catch (Exception ex) {
					swappingProportionTextField.setText(tabooListLength.toString());							
				}

				consoleTextArea.setText("");
				UserInterface.this.controller.calculate(maxIteration, neighborhoodSize, tabooListLength, randomSwappingNumber, swappingProportion);
			}
		});				
	}
	
	private void create_view_panel() {
		viewPanel = new JPanel(new GridLayout(1, 1));
		
		consoleTextArea = new JTextArea();
		consoleTextArea.setFont(new Font("Consolas", 1, 12));
		consoleTextArea.setEditable(false);
		JScrollPane consoleScroll = new JScrollPane(consoleTextArea);
		consoleScroll.setAutoscrolls(true);
		
		
		mapPanel = new JPanel(null);
		JScrollPane mapScroll = new JScrollPane(mapPanel);
		//mapScroll.setAutoscrolls(true);
		
		JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, mapScroll, consoleScroll);
		split.setResizeWeight(0.7);
		viewPanel.add(split);
	}
}
